package video

import (
	"bytes"
	"database/sql/driver"
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"unicode"
	"unicode/utf8"

	"github.com/asticode/go-astisub"
)

type Subtitles struct{}
type SubtitleConf struct {
	StartMill    int64  `json:"startMill"`    //开始毫秒
	StartSeconds int64  `json:"startSeconds"` //开始秒
	EndMill      int64  `json:"endMill"`      //结束毫秒
	EndSeconds   int64  `json:"endSeconds"`   //结束秒
	Text         string `json:"text"`         //文本
}

type SubtitleConfSli []SubtitleConf

func (t SubtitleConfSli) Value() (v driver.Value, err error) {
	return json.Marshal(t)
}

// 实现 sql.Scanner 接口，Scan 将 value 扫描至 Json
func (t *SubtitleConfSli) Scan(value interface{}) error {
	bytes, ok := value.([]byte)
	if !ok {
		return errors.New(fmt.Sprint("Failed to unmarshal JSON value:", value))
	}

	err := json.Unmarshal(bytes, t)
	return err
}

func NewSubtitles() *Subtitles { return &Subtitles{} }

func (m *Subtitles) GenSubtitleSRT(text string, durationTick int64) (conf []SubtitleConf) {
	durationTickMillis := durationTick / 10000
	mill := durationTickMillis % 1000
	sec := durationTickMillis / 1000
	//去除标点符号
	newText := strings.Map(func(c rune) rune {
		if unicode.IsPunct(c) {
			return -1
		}
		return c
	}, text)
	//计算每个字符大概占用多少毫秒
	millPer := durationTickMillis / int64(utf8.RuneCountInString(newText))
	// 使用自定义分隔函数切分文案
	sentences := strings.FieldsFunc(text, func(c rune) bool {
		return unicode.IsPunct(c)
	})
	sentenceTemp := int64(0)
	curSubtitleConf := SubtitleConf{}
	for i, sentence := range sentences {
		sentenceTemp = int64(utf8.RuneCountInString(sentence)) + sentenceTemp
		durationSentence := millPer * sentenceTemp
		millSentence := durationSentence % 1000
		secSentence := durationSentence / 1000
		new := SubtitleConf{
			StartMill:    curSubtitleConf.EndMill,
			StartSeconds: curSubtitleConf.EndSeconds,
			Text:         strings.TrimSpace(strings.ReplaceAll(sentence, "\r\n", "")),
		}
		if i == len(sentences)-1 {
			new.EndMill = mill
			new.EndSeconds = sec
		} else {
			new.EndMill = millSentence
			new.EndSeconds = secSentence
		}
		conf = append(conf, new)
		curSubtitleConf = new
	}
	return
}

func (m *Subtitles) FormatTime(seconds int64) string {
	hours := seconds / 3600
	minutes := (seconds % 3600) / 60
	seconds = seconds % 60
	return fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds)
}

func (m *Subtitles) GenSrtBytes(conf SubtitleConfSli) (byt []byte, err error) {
	// []byte("1\n00:01:00.000 --> 00:02:00.000\nCredits")
	strSli := []string{}
	for i, subtitleConf := range conf {
		startTime := fmt.Sprintf("%s.%d", m.FormatTime(subtitleConf.StartSeconds), subtitleConf.StartMill)
		endTime := fmt.Sprintf("%s.%d", m.FormatTime(subtitleConf.EndSeconds), subtitleConf.EndMill)
		strSli = append(strSli, fmt.Sprintf("%d\n%s --> %s\n%s", i+1, startTime, endTime, subtitleConf.Text))
	}
	str := strings.Join(strSli, "\n")
	byt = []byte(str)
	return
}

func (m *Subtitles) CreateSRTFile(filename string, conf SubtitleConfSli) (err error) {
	byt, _ := m.GenSrtBytes(conf)
	s, _ := astisub.ReadFromSRT(bytes.NewReader(byt))
	return s.Write(filename)
}
